//Request
function RequestOptions(options)
{
	this.headers =
	{
		"Accept": "text/javascript, text/html, application/xml, text/xml, */*"
	};

	for (var n in options)
	{
		if (n == "headers")
		{
			var headers = options[n];

			for (var n2 in headers)
			{
				this.headers[n2] = headers[n2];
			}
		}
		else
		{
			this[n] = options[n];
		}
	}
}

RequestOptions.prototype =
{
	"X-Requested-With": "XMLHttpRequest",
	method: "get",
	async : false,
	contentType: "application/x-www-form-urlencoded",
	encoding: "UTF-8"
}

/**
 * <p>XMLHttpRequest请求包装类，默认为同步方式。
 * 若希望使用异步方式,在调用send方法时指定第二个参数async=true
 * 通过setXXXListener,addXXXListener 添加事件回调函数。
 * 支持的事件有 [start,receiving,success,failure,finish]
 * 以添加自定义行为</p>
 * eg:
 * <code><pre>
 * new Request(url,{username:xxx,password:yyy})
 *   //若成功，提示success
 *   .setSuccessListener (function(){alert("success");})
 *   //若失败，提示fail
 *   .setFailureListener (function(){alert("fail");})
 *   //传送 参数表：param1=1,指定请求方式为异步
 *   .send({param1:1},true);</pre>
 * </code>
 * @constructor
 * @param {String} url 请求地址
 * @param {Object} [options] 请求选项 
 */
function Request(url, options) 
{
	/** @protected */
	this.transport = new XMLHttpRequest;
	/** @protected */
	this.attachedListener = [];
	/** @protected */
	this.url = url;
	/** @protected */
	this.options = new RequestOptions(options);
	var _this = this;
	this.onreadystatechange = function()
	{
		switch(_this.transport.readyState)
		{
			case 0: //(未初始化)	对象已建立，但是尚未初始化（尚未调用open方法）
			case 1: // (初始化)	对象已建立，尚未调用send方法
				break;
			case 2: // (发送数据)	send方法已调用，但是当前的状态及http头未知
				fireEvent(_this, "onStart");
				break;
			case 3: // (数据传送中)	已接收部分数据，因为响应及http头不全，这时通过responseBody和responseText获取部分数据会出现错误，
				fireEvent(_this, "onReceiving");
				break;
			case 4: // (完成)	数据接收完毕,此时可以通过通过responseBody和responseText获取完整的回应数据
				if(_this.isSuccess() == false)
				{
					fireEvent(_this, "onSuccess");
				}
				else
				{
					fireEvent(_this, "onFailure");
				}
				fireEvent(_this, "onFinish");
				_this.free = true;
				_this.transport.onreadystatechange = $JSI.$void;
				break;
		}
	};
};

var $p = Request.prototype;

/**
 * 指示当前Request是否空闲
 * @private
 * @type Boolean
 * @id Request.prototype.free
 */
$p.free = true;

/**
 * 设置请求http头。（在每次send调用之前有效）
 * @public
 * @param {String} key 名称
 * @param {String} value 值
 * @return {Request} request 本身，以便继续操作
 * @id Request.prototype.setHeader
 */
$p.setHeader = function(key, value)
{
	asyncheaders[key] = value;
	return this;
};
/**
 * 发送请求
 * @public
 * @param {String|Object} params 参数
 * @param {Boolean} [async=false] 是否异步执行
 * @return {Request} request 本身,以便继续操作
 * @id Request.prototype.send
 */
$p.send = function(params, async)
{
	this.free = false;
	var opts = this.options, headers = opts.headers, conn = this.transport, n;
	params = buildQueryString(params);
	async = async == null ? opts.async : async;

	if (opts.method == "post")
	{
		conn.open(opts.method, this.url, async);
		/* Force "Connection: close" for Mozilla browsers to work around
		 * a bug where XMLHttpReqeuest sends an incorrect Content-length
		 * header. See Mozilla Bugzilla #246651.
		 */
		if (conn.overrideMimeType)
		{
			headers["Connection"] = "close";
		}
	}
	else
	{
		conn.open(opts.method, this.url + (params
			? (this.url.match(/\?/)	? "&" : "?") + params
			: ""),
			async);
	}
	conn.onreadystatechange = this.onreadystatechange;

	for (n in headers)
	{
		conn.setRequestHeader(n, headers[n]);
	}
	conn.send(opts.method == "post" ? params : null);
	return this;
};
	
/**
 * 该对象是否空闲(是否可再发送请求).
 * @see #send(params, async);
 * @public
 * @return {Boolean} 状态
 * @id Request.prototype.isFree
 */
$p.isFree = function()
{
	return this.free;
}

/**
 * 判断请求是否成功
 * @public
 * @return {boolean|null} 成败或未知(null)
 * @id Request.prototype.isSuccess
 */
$p.isSuccess = function()
{
	var stus = this.transport.status;
	if(stus == null || stus == 0)
	{
		return null;
	}
	else
	{
		return stus >= 200 && stus < 300;
	}
};
	
/**
 * 当前请求响应头
 * @public
 * @param {String} name 响应头名称
 * @return {String} header值
 * @id Request.prototype.getHeader
 */
$p.getHeader = function(name)
{
	if(this.transport.readyState >= 3)
	{
		return this.transport.getResponseHeader(name);
	}
	else
	{
		$log.error("response not complete");
	}
};
/**
 * 将当前请求返回文本当脚本程序执行
 * @public
 * @return {mixed} 执行结果
 * @id Request.prototype.evalResult
 */
$p.evalResult = function()
{
	if(this.transport.readyState == 4)
	{
		return eval(this.transport.responseText);
	}
	else
	{
		$log.error("response not complete");
	}
};
/**
 * 将当前请求返回数据
 * @public
 * @return {String|XMLDocument} 文本 或 XMLDocument
 * @id Request.prototype.getResult
 */
$p.getResult = function()
{
	var conn = this.transport;
	if(/\/xml/.test(this.getHeader("Content-Type")))
	{
		//text/xml,application/xml...
		if(conn.readyState == 4)
		{
			return conn.responseXML;
		}
	}
	else
	{
		if(conn.readyState >= 3)
		{
			return conn.responseText;
		}
	}
	$log.error("response not complete");
};
	
/**
 * 将当前请求返回XMLDocument
 * @public
 * @param {Boolean} [force=false] translate to xml document if only text value;
 * @return XMLDocument
 * @id Request.prototype.getXML
 */
$p.getXML = function(force)
{
	var conn = this.transport;
	if(conn.readyState == 4)
	{
		return force ? toXMLResult(conn) : conn.responseXML;
	}
	else
	{
		$log.error("response not complete");
	}
};

/**
* 将当前请求返回XMLDocument文本
* @public
* @param {Boolean} [force=false] translate to text value if only xml value;
* @return String
* @id Request.prototype.getText
*/
$p.getText = function(force)
{
	var conn = this.transport;
	if (conn.readyState >= 3)
	{
		return force ? toTextResult(conn) : conn.responseText;
	}
	else
	{
		$log.error("response not complete");
	}
};

function buildEventHandle(type)
{
	var listenerPostfix = type.substr(2) + "Listener";
	$p["set" + listenerPostfix] = function(listener)
	{
		this[type] = listener;
		return this;
	};
	$p["add" + listenerPostfix] = function(listener)
	{
		var list = this.attachedListener[type];
		list ? list.push(listener) : this.attachedListener[type] = [listener];
		return this;
	};
	listenerPostfix = null;
}

for (var requestEvents = ["onStart", "onReceiving", "onSuccess", "onFailure", "onFinish"], reqEventLen = requestEvents.length - 1; reqEventLen >= 0; reqEventLen--)
{
	buildEventHandle(requestEvents[reqEventLen]);
}
buildEventHandle = requestEvents = reqEventLen = $p = null;
/**
 * 设置请求开始的事件回调函数.
 * @id Request.prototype.setStartListener
 * @param {Function} cb 回调函数
 * @public
 * @return {Request} request 本身,以便继续操作
 */
/**
 * 添加附加请求开始的事件回调函数.
 * @id Request.prototype.addStartListener
 * @public
 * @param {Function} cb 回调函数
 * @return {Request} request 本身,以便继续操作
 */

/**
 * 设置开始接受数据事件回调函数.
 * @id Request.prototype.setReceivingListener
 * @param {Function} cb 回调函数
 * @public
 * @return {Request} request 本身,以便继续操作
 */
/**
 * 添加附加开始接受数据事件回调函数.
 * @id Request.prototype.addReceivingListener
 * @param {Function} cb 回调函数
 * @public
 * @return {Request} request 本身,以便继续操作
 */

/**
 * 设置请求成功的事件回调函数
 * @id Request.prototype.setSuccessListener
 * @public
 * @param {Function} cb 回调函数
 * @return {Request} request 本身,以便继续操作
 */
/**
 * 添加附加请求成功的事件回调函数
 * @id Request.prototype.addSuccessListener
 * @public
 * @param {Function} cb 回调函数
 * @return {Request} request 本身,以便继续操作
 */
/**
 * 设置请求失败的事件回调函数
 * @id Request.prototype.setFailureListener
 * @public
 * @param {Function} cb 回调函数
 * @return {Request} request 本身,以便继续操作
 */
/**
 * 添加附加请求失败的事件回调函数
 * @id Request.prototype.addFailureListener
 * @public
 * @param {Function} cb 回调函数
 * @return {Request} request 本身,以便继续操作
 */
/**
 * 设置请求结束的事件回调函数
 * @id Request.prototype.setFinishListener
 * @public
 * @param {Function} cb 回调函数
 * @return {Request} request 本身,以便继续操作
 */

/**
 * 添加附加请求结束的事件回调函数
 * @id Request.prototype.addFinishListener
 * @public
 * @param {Function} cb 回调函数
 * @return {Request} request 本身,以便继续操作
 */

function fireEvent(requset, key)
{
	if (requset[key]instanceof Function)
	{
		requset[key]();
	}
	var listeners = requset.attachedListener[key];

	if (listeners)
	{
		for (var i = 0; i < listeners.length; i++)
		{
			listeners[i].apply(requset);
		}
	}
}

function toXMLResult(transport)
{
	var result = transport.responseXML;

	if (/\/xml/.test(transport.getResponseHeader("Content-Type")) || result && result.documentElement
		&& result.documentElement.hasChildNodes())
	{
		return result;
	}
	return new DOMParser().parseFromString(transport.responseText, "text/xml");
}

function toTextResult(transport)
{
	var result = transport.responseText;

	if (!result && /\/xml/.test(transport.getResponseHeader("Content-Type")))
	{
		result = transport.responseXML;
		result = result.xml ? result.xml : new XMLSerializer().serializeToString(result);
	}
	return result;
}

/**
 * 根据params参数构建http参数表达式
 * @public
 * @return String
 */
function buildQueryString(params)
{
	if(typeof params == "string")
	{
		return params;
	}
	else if(params instanceof Array)
	{
		return params.join("&");
	}
	else if(params instanceof Object)
	{
		var paramArray = [], n1, n2, n3;
		for(n1 in params)
		{
			n2 = params[n1];
			n3 = n1 + "=";
			if(n2 instanceof Array)
			{
				paramArray.push(n3 + n2.join("&"+n3));
			}
			else
			{
				paramArray.push(n3 + String(n2));
			}
		}
		return paramArray.join("&");
	}
	else
	{
		return params || "";
	}
}